/**
 *
 * \file MemoryPoolManager.cpp
 *	\brief MemoryPoolManager declaration class
 * \author Edouard ROGE
 * \date 06 august 2012
 *
 */

#include <math.h>
#include <iostream>
#include "Core/Log/LogManager.h"
#include "MemoryPoolManager.h"

namespace Core
{
	namespace Memory
	{
		MemoryPoolManager::MemoryPoolManager()
		{
			LOG_INFO("Creating new Memory Manager");
			m_MemoryPools.resize(14);
			for (int32 i = 0; i < 6; ++i)
				m_MemoryPools[i].BuildPool(2000, (int32)pow(2.0, i + 5));

			for (int32 i = 6; i < 10; ++i)
				m_MemoryPools[i].BuildPool(1000, (int32)pow(2.0, i + 5));

			for (int32 i = 10; i < 14; ++i)
				m_MemoryPools[i].BuildPool(500, (int32)pow(2.0, i + 5));
		}

		MemoryPoolManager::~MemoryPoolManager()
		{

		}

		void * MemoryPoolManager::Allocate(size_t _iSize)
		{
			int32 index = (int32)ceil(log((float)_iSize) / log(2.0f)) - 5;
			index = (index >= 0 ? index : 0);
			return m_MemoryPools[index].Allocate(_iSize);
		}

		void MemoryPoolManager::Free(void * _ptr)
		{
			uint32 i = 0;
			while (i < m_MemoryPools.size() && !m_MemoryPools[i].IsAddressBelongingTo(_ptr))
				++i;

			if (i < m_MemoryPools.size())
			{
				m_MemoryPools[i].Free(_ptr);
			}
			else
			{
				LOG_ERROR("Can't delete %p", _ptr);
			}
		}

		std::vector<void*> MemoryPoolManager::GetMemoryLeaks() const
		{
			std::vector<void *> res;
			for (uint32 i = 0; i<m_MemoryPools.size(); ++i)
				m_MemoryPools[i].GetMemoryLeaks(res);

			return res;
		}

		void MemoryPoolManager::CheckLeaks(bool _bClearLeaks)
		{
			std::vector<void*> leaks = GetMemoryLeaks();
			uint32 nLeaks = leaks.size();
			if (nLeaks>0)
			{
				LOG_ERROR("%d memory leaks detected ! Please check your code ...", nLeaks);
				for (uint32 i = 0; i < nLeaks; ++i)
					LOG_ERROR("%p", leaks[i]);
			}

			if (_bClearLeaks)
			{
				for (uint32 i = 0; i < nLeaks; ++i)
					free(leaks[i]);
			}
		}
	}
}
